#pragma once

#include "Controller/Controller.hpp"
#include "Data/CurveData.hpp"

/** @class Command
  * @brief Абстрактный класс, определяющий общий интерфейс всех команд.
  *
  * Класс Command инкапсулирует запрос как объект, позволяя тем самым задавать параметры клиетнов для обработки соответствующих запросов,
  * ставить запросы в очередь или протоколировать их, а также поддерживать отмену операций
  */
class Command
{
protected:
    bool m_undoable; ///< Признак наличия возможности отменить команду
public:
    
    /**
      * Выполнить действие
      * Конкретные подклассы Command реализуют эту процедуру, чтобы она посылала соответствующий запрос
      */
    virtual void execute() = 0;

    /**
      * Отменить выполнение действия.
      * Конкретные подклассы Command, являющиеся отменяемыми, реализуют эту процедуру.
      * Неотменяемые команды оставляют процедуру непереопределенной (пустой)
      */
    virtual void unexecute(){}

    /**
      * Виртуальный деструктор
      */
    virtual ~Command(){}
    
protected:
  
    /**
      * Конструктор
      */
    Command();
};


/** @class SimpleCommand
  * @brief Класс, реализующий просую команду
  *
  * Шаблонный класс SimpleCommand реализует простую команду, которая не допускает отмены и не требует аргументов
  * Параметризуется типом получателя действия. Хранит связь между объектом-получателем и действием
  */
template <class Receiver>
class SimpleCommand : public Command
{
    typedef void (Receiver::* Action)();
    Action m_action;    ///< Действие (указатель на функцию класса Receiver
    Receiver *m_receiver;    ///< Получатель
public:
    /**
      * Конструктор
      *
      * @param r Получатель
      * @param a Действие
      */
    SimpleCommand(Receiver *r,Action a):m_receiver(r), m_action(a){}

    /**
      * Вызывает функцию с адресом m_action у объекта m_receiver
      */
    virtual void execute(){(m_receiver->*m_action)();}

    /**
      * Деструктор
      */
    ~SimpleCommand(){}
 };

//LoadDataCommand
class LoadDataCommand : public Command
{
private:
    char *m_path;
public:
    LoadDataCommand(char *path, CurveData *data);
	LoadDataCommand(char *path);
    virtual ~LoadDataCommand(){}
    virtual void execute(); 
    virtual void unexecute();
};

//GetValueCommand
class GetValueCommand : public Command
{
private:
    CurveData *m_data;
    double m_x;
public:
    GetValueCommand(double x, CurveData *data);
    virtual ~GetValueCommand(){}
    virtual void execute(); 
};

